#include "sData.h"

#include <stdlib.h>
#include <sstream>
#include <stdio.h>
#include <fstream>
#include <Poco/DOM/Document.h>
#include <Poco/DOM/NodeIterator.h>
#include <Poco/Base64Encoder.h>
#include <Poco/Base64Decoder.h>
#include <Poco/StreamCopier.h>
#include "misc/Interface.h"
#include "misc/Debug.h"
#include "server/net/NetworkControl.h"
#include "server/file/FileControl.h"
/*********************************************************/
void sData::execute()
{
	Interface& iface = Interface::Instance();
	FileControl& files = FileControl::Instance();

	if ( shell ) {
	} else {
		iface << "Received: " << size << " bytes of data for file: " << fileName << std::endl;
		iface.flush();

		files.addChunk(fileName, order, data, fSize);
	}

	ack();
}
/*********************************************************/
std::string sData::serialize() const
{
	NetworkControl& ns = NetworkControl::Instance();
	std::ostringstream		xml;
	std::ostringstream		datastr;
	std::ostringstream		filestr;
	id = ns.getID();

	// The data needs to be a multiple of 6 bits
	std::string data_ = data;
	while ( ((data_.length()*8) % 6) != 0 ) {
		data_.append("\n");
	}

	std::string fileName_ = fileName;
	while ((( fileName_.length()*8) % 6) != 0 ) {
		fileName_.append("\n");
	}

	// We encode the data so it doesn't collide with any xml tags
	Poco::Base64Encoder	encoder(datastr);
	encoder << data_;

	Poco::Base64Encoder	encoder2(filestr);
	encoder2 << fileName_;

	// Build the xml string for this job
	xml << "<GS id='" << id << "'>";
	xml << "<Data>";
	xml << "<type>";
	if ( shell ) xml << "1</type>";
	else xml << "0</type>";
	xml << "<order>" << order << "</order>";
	xml << "<data>" << datastr.str() << "</data>";
	xml << "<file>" << filestr.str() << "</file>";
	xml << "<size>" << size << "</size>";
	xml << "<filesize>" << fSize << "</filesize>";
	xml << "</Data>";
	xml << "</GS>";

	return( xml.str() );
}
/*********************************************************/
void sData::deserialize(Poco::XML::NodeIterator& it)
{
	Poco::XML::Node* node = it.nextNode();
	if ( node->nodeName() != "type") {
		throw(std::logic_error("Job type data given, data field 'type' missing or incorrectly ordered!"));
	} else {
		if ( node->innerText() == "1" ) {
			shell = true;
		} else {
			shell = false;
		}
	}

	node = it.nextNode();
	if ( node->nodeName() != "order" ) {
		throw(std::logic_error("Job type data given, data field 'order' missing or incorrectly ordered!"));
	} else {
		order = atoi(node->innerText().c_str());
	}

	node = it.nextNode();
	if ( node->nodeName() != "data" ) {
		throw(std::logic_error("Job type data given, data field 'data' missing or incorrectly ordered!" ));
	} else {
		// Decode the data string from a Base64 representation
		std::ostringstream	ostr;
		std::istringstream	istr;
	
		// Decode the result
		istr.str(node->innerText());			// Pass it into a inputstringstream
		Poco::Base64Decoder	decoder(istr);		// decode it...

		// Copy the decoded data to the local storage
		Poco::StreamCopier::copyStream(decoder, ostr);
		std::string result = ostr.str();

		// Store the data
		data = result;
	}

	node = it.nextNode();
	if ( node->nodeName() != "file" ) {
		throw(std::logic_error("Job type data given, data field 'data' missing or incorrectly ordered!" ));
	} else {
		// Decode the data string from a Base64 representation
		std::ostringstream	ostr;
		std::istringstream	istr;
	
		// Decode the result
		istr.str(node->innerText());			// Pass it into a inputstringstream
		Poco::Base64Decoder	decoder(istr);		// decode it...

		// Copy the decoded data to the local storage
		Poco::StreamCopier::copyStream(decoder, ostr);
		std::string result = ostr.str();

		// Remove any appended newlines to align for base 64 encoding
		for ( unsigned int i=0; i<result.length(); i++ ) {
			if ( result[i] == '\n' ) {
				result.erase(i,1);
				i = 0;	
			}
		}

		// Store the data
		fileName = result;
	}

	node = it.nextNode();
	if ( node->nodeName() != "size" ) {
		throw(std::logic_error("Message data given, missing field size!"));
	} else {
		size = atol(node->innerText().c_str());

		// Remove any appended newlines
		data.erase(size, data.length() - size);
	}

	node = it.nextNode();
	if ( node->nodeName() != "filesize" ) {
		throw(std::logic_error("Message data given, missing field filesize"));
	} else {
		fSize = atol(node->innerText().c_str());
	}
}
/*********************************************************/
void sData::setFileSize(const unsigned long& s)
{
	fSize = s;
}
/*********************************************************/
unsigned long sData::getFileSize() const
{
	return fSize;
}
/*********************************************************/
void sData::setFileName(const std::string& f)
{
	fileName = f;
}
/*********************************************************/
std::string sData::getFileName() const
{
	return fileName;
}
/*********************************************************/
void sData::setShell(const bool& sh)
{
	shell = sh;
}
/*********************************************************/
bool sData::getShell() const
{
	return shell;
}
/*********************************************************/
void sData::setData(const std::string& d)
{
	data = d;
	size = d.length();
}
/*********************************************************/
void sData::setOrder(const unsigned int& p)
{
	order = p;
}
/*********************************************************/
std::string sData::getData() const
{
	return data;
}
/*********************************************************/
unsigned int sData::getOrder() const
{
	return order;
}
/*********************************************************/
